package models

import (
	"context"
	"fmt"
	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"go-chain-data/global"
	"go-chain-data/utils"
	"math/big"
	"strings"
)

type SwapTransactionInfo struct {
	ChainName       string `bson:"chainName"`
	ChainID         uint   `bson:"chainId"`      // 链的唯一标识符
	Sender          string `bson:"sender"`       // 触发交换的地址
	From            string `bson:"from"`         // 交易发起地址
	Amount0In       string `bson:"amount0In"`    // Token0输入的数量
	Amount1In       string `bson:"amount1In"`    // Token1输入的数量
	Amount0Out      string `bson:"amount0Out"`   // Token0输出的数量
	Amount1Out      string `bson:"amount1Out"`   // Token1输出的数量
	Value           string `bson:"value"`        // 成交量
	Price           string `bson:"price"`        // 成交价
	Type            int    `bson:"type"`         // 1买2卖
	To              string `bson:"to"`           // 接收输出代币的地址
	Timestamp       int64  `bson:"timestamp"`    // 时间戳
	TokenAddress    string `bson:"tokenAddress"` // 底池地址
	BlockNumber     uint64 `bson:"blockNumber"`
	TransactionHash string `bson:"transactionHash"`
}

func ParseSwapEventLogToStruct(l types.Log, tx *types.Transaction, contractAbi string, chainName string, chainId uint, blockNumber uint64, usdtAddress string) error {
	parsedABI, err := abi.JSON(strings.NewReader(contractAbi))
	if err != nil {
		fmt.Println("解析合约出错:", err)
		return err
	}

	event := "Swap"
	if _, ok := parsedABI.Events[event]; !ok {
		return fmt.Errorf("未找到%s事件", event)
	}

	result := new(SwapTransactionInfo)
	if len(l.Topics) != 3 {
		return fmt.Errorf("log topics数量不符合预期")
	}

	signer := types.LatestSignerForChainID(big.NewInt(int64(chainId)))
	from, err := types.Sender(signer, tx)
	if err != nil {
		return fmt.Errorf("无法解析交易: %w", err)
	}
	// 解析indexed参数
	result.From = from.Hex()
	result.Sender = common.HexToAddress(l.Topics[1].Hex()).Hex()
	result.To = common.HexToAddress(l.Topics[2].Hex()).Hex()
	// 解析非indexed参数
	item := make(map[string]interface{})

	err = parsedABI.UnpackIntoMap(item, event, l.Data)
	if err != nil {
		fmt.Println("解析abi出错:", err)
		return err
	}
	//先从swap_info获取底池信息 在通过token表获取代币信息
	pair, err := GetSwapInfoByAddress(l.Address.String())
	if err != nil {
		fmt.Println("获取底池信息出错:", err)
		return err
	}
	//获取redis代币信息
	token0, _ := GetTokenInfoByAddress(pair.Token0Address)
	token1, _ := GetTokenInfoByAddress(pair.Token1Address)
	//t, _ := json.Marshal(token0)
	//fmt.Println(string(t), "987")
	//t, _ = json.Marshal(item)
	//fmt.Println(string(t), "654")
	result.Amount0In = utils.WeiBigIntToEtherStr(item["amount0In"].(*big.Int), token0.Decimals)   //USDT入
	result.Amount1In = utils.WeiBigIntToEtherStr(item["amount1In"].(*big.Int), token1.Decimals)   //TOKEN入
	result.Amount0Out = utils.WeiBigIntToEtherStr(item["amount0Out"].(*big.Int), token0.Decimals) //USDT出
	result.Amount1Out = utils.WeiBigIntToEtherStr(item["amount1Out"].(*big.Int), token1.Decimals) //TOKEN出

	//计算value
	token0Value := new(big.Int).Sub(item["amount0In"].(*big.Int), item["amount0Out"].(*big.Int))
	token1Value := new(big.Int).Sub(item["amount1In"].(*big.Int), item["amount1Out"].(*big.Int))

	if pair.Token0Address == usdtAddress {
		if token0Value.Cmp(big.NewInt(0)) < 0 {
			result.Type = 2
		} else {
			result.Type = 1
		}
	}

	if pair.Token1Address == usdtAddress {
		if token0Value.Cmp(big.NewInt(0)) < 0 {
			result.Type = 1
		} else {
			result.Type = 2
		}
	}

	token0Value = token0Value.Abs(token0Value)
	token1Value = token1Value.Abs(token1Value)

	result.Value = utils.WeiBigIntToEtherStr(token0Value, token0.Decimals)
	//价格计算还有问题
	//fmt.Println(token1Value)
	//fmt.Println(token0Value)
	//fmt.Println(token1.Decimals)
	//fmt.Println(token0.Decimals)
	result.Price, _ = utils.BigIntDivToString(token1Value, token0Value, token1.Decimals, token0.Decimals, 18, token1.Symbol)
	result.TokenAddress = l.Address.String()
	result.TransactionHash = tx.Hash().Hex()

	result.ChainID = chainId

	result.Timestamp = tx.Time().Unix()
	result.BlockNumber = blockNumber
	result.ChainName = chainName

	SwapTransactionClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("swap_transaction_info")
	_, err = SwapTransactionClient.InsertOne(context.Background(), result)
	if err != nil {
		return err
	}
	return nil
}
